home *** CD-ROM | disk | FTP | other *** search
/ Collection of Tools & Utilities / Collection of Tools and Utilities.iso / pascal / xlibpas2.zip / XGIF2.PAS < prev    next >
Pascal/Delphi Source File  |  1994-06-12  |  18KB  |  756 lines

  1. unit XGIF2;
  2. { ************************************************
  3.   **    GIF Decoding and Encoding procedures    **
  4.   **        for Borland/Turbo Pascal 7.0        **
  5.   **                                            **
  6.   **     Written by Tristan Tarrant, 1994       **
  7.   **                                            **
  8.   **        ( Supports GIF87a/GIF89a )          **
  9.   ************************************************ }
  10.  
  11. interface
  12.  
  13. uses
  14.     Dos;
  15.  
  16. const
  17.     { Error constants used in GIF decoder }
  18.     GoodRead      = 0;
  19.     BadFile       = 1;
  20.     BadRead       = 2;
  21.     UnexpectedEOF = 3;
  22.     BadCode       = 4;
  23.     BadFirstCode  = 5;
  24.     NoFile        = 6;
  25.     BadSymbolSize = 7;
  26.     NoCode        = -1;
  27.     Gif87a        = 0;
  28.     Gif89a        = 1;
  29.  
  30.     { These values will be masked with the codes output from the
  31.         decoder to remove spurious bits }
  32.     CodeMask : array[1..13] of word =
  33.         ( $0000,
  34.             $0001, $0003,
  35.             $0007, $000F,
  36.             $001F, $003F,
  37.             $007F, $00FF,
  38.             $01FF, $03FF,
  39.             $07FF, $0FFF );
  40.  
  41. Type
  42.     GifLineProcType = procedure( Var pixels; line, width : integer );
  43.     GifPixelProcType = function : integer;
  44.     TByteArray = Array[0..0] of byte;
  45.     TIntArray = Array[0..0] of integer;
  46.  
  47. Var
  48.     { Pointers to custom procedures to deal with lines. GifOutLineProc
  49.       is called with three parameters : an untyped var, containing
  50.       the uncompressed data, and two integer values, containing the
  51.       line number and the width of the line.
  52.       GifInPixelProc should instead return a pixels value, -1 if at the
  53.       end of the data. }
  54.  
  55.     GifOutLineProc : GifLineProcType;
  56.     GifInPixelProc : GifPixelProcType;
  57.     GifPalette : array[0..767] of byte;
  58.  
  59.  
  60.  
  61. function LoadGif( f : string ) : integer;
  62. function SaveGif( f : string; width, depth, bits : integer; var palette ) : integer;
  63. function GifError( ErrorCode : integer ) : string;
  64.  
  65. Implementation
  66.  
  67. type
  68.     GifHeader =
  69.         record
  70.             sig : array[1..6] of char;
  71.             screenwidth, screendepth : word;
  72.             flags, background, aspect : byte;
  73.         end;
  74.  
  75.     ImageBlock =
  76.         record
  77.             left, top, width, depth : word;
  78.             flags : byte;
  79.         end;
  80.  
  81.     FileInfo =
  82.         record
  83.             width, depth, bits,
  84.             flags, background : integer;
  85.             palette : array[1..768] of byte;
  86.         end;
  87.  
  88.     ControlBlock =
  89.         record
  90.             blocksize, flags : byte;
  91.             delay : word;
  92.             transparentcolour, terminator : byte;
  93.         end;
  94.  
  95.     PlainText =
  96.         record
  97.             blocksize : byte;
  98.             left, top, gridwidth, gridheight : word;
  99.             cellwidth, cellheight, forecolour, backcolour : byte;
  100.         end;
  101.  
  102.     Application =
  103.         record
  104.             blocksize : byte;
  105.             applstring : array[1..8] of char;
  106.             authentication : array[1..3] of char;
  107.         end;
  108.  
  109.  
  110. const
  111.     TableSize = 5003;
  112.     LargestCode = 4095;
  113.  
  114. function UnpackImage( var F : File; bits : integer; Var fi : FileInfo ) : integer;
  115. var
  116.     bits2, codesize, codesize2, nextcode, thiscode,
  117.     oldtoken, currentcode, oldcode, bitsleft, blocksize,
  118.     line, pass, byt, p, q, u : integer;
  119.     b : array[0..255] of byte;
  120.     linebuffer, firstcodestack, lastcodestack : ^TByteArray;
  121.     codestack : ^TIntArray;
  122. const
  123.     wordmasktable : array[0..15] of word =
  124.         ( $0000, $0001, $0003, $0007, $000F, $001F,
  125.             $003F, $007F, $00FF, $01FF, $03FF, $07FF,
  126.             $0FFF, $1FFF, $3FFF, $7FFF );
  127.     inctable : array[0..4] of integer = ( 8, 8, 4, 2, 0 );
  128.     starttable : array[0..4] of integer = ( 0, 4, 2, 1, 0 );
  129. begin
  130.     pass := 0;
  131.     line := 0;
  132.     byt := 0;
  133.     p := 0;
  134.     q := 0;
  135.     blocksize := 0;
  136.     fillchar( b, 256, 0 );
  137.     bitsleft := 8;
  138.     if ( bits < 2 ) or ( bits > 8 ) then
  139.     begin
  140.         UnpackImage := BadSymbolSize;
  141.         exit;
  142.     end;
  143.     bits2 := 1 shl bits;
  144.     nextcode := bits2 + 2;
  145.     codesize := bits + 1;
  146.     codesize2 := 1 shl codesize;
  147.     oldcode := NoCode;
  148.     oldtoken := NoCode;
  149.     getmem( firstcodestack, 4096 );
  150.     getmem( lastcodestack, 4096 );
  151.     getmem( codestack, 8192 );
  152.     getmem( linebuffer, fi.width );
  153.     while true do
  154.     begin
  155.         if bitsleft = 8 then
  156.         begin
  157.             inc(p);
  158.             if p>=q then
  159.             begin
  160.                 blocksize := 0;
  161.                 blockread( F, blocksize, 1);
  162.                 if blocksize>0 then
  163.                 begin
  164.                     p:=0;
  165.                     blockread( F, b, blocksize, q );
  166.                     if q<>blocksize then
  167.                     begin
  168.                         freemem( firstcodestack, 4096 );
  169.                         freemem( lastcodestack, 4096 );
  170.                         freemem( codestack, 8192 );
  171.                         freemem( linebuffer, fi.width );
  172.                         UnpackImage := UnexpectedEOF;
  173.                         exit;
  174.                     end;
  175.                 end else
  176.                 begin
  177.                     freemem( firstcodestack, 4096 );
  178.                     freemem( lastcodestack, 4096 );
  179.                     freemem( codestack, 8192 );
  180.                     freemem( linebuffer, fi.width );
  181.                     UnpackImage := UnexpectedEOF;
  182.                     exit;
  183.                 end;
  184.             end;
  185.             bitsleft := 0;
  186.         end;
  187.         thiscode := b[p];
  188.         currentcode := codesize + bitsleft;
  189.         if currentcode <=8 then
  190.         begin
  191.             b[p] := b[p] shr codesize;
  192.             bitsleft := currentcode;
  193.         end else
  194.         begin
  195.             inc(p);
  196.             if p>=q then
  197.             begin
  198.                 blocksize := 0;
  199.                 blockread( F, blocksize, 1);
  200.                 if blocksize>0 then
  201.                 begin
  202.                     p:=0;
  203.                     blockread( F, b, blocksize, q );
  204.                     if q<>blocksize then
  205.                     begin
  206.                         freemem( firstcodestack, 4096 );
  207.                         freemem( lastcodestack, 4096 );
  208.                         freemem( codestack, 8192 );
  209.                         freemem( linebuffer, fi.width );
  210.                         UnpackImage := UnexpectedEOF;
  211.                         exit;
  212.                     end;
  213.                 end else
  214.                 begin
  215.                     freemem( firstcodestack, 4096 );
  216.                     freemem( lastcodestack, 4096 );
  217.                     freemem( codestack, 8192 );
  218.                     freemem( linebuffer, fi.width );
  219.                     UnpackImage := UnexpectedEOF;
  220.                     exit;
  221.                 end;
  222.             end;
  223.             thiscode := thiscode or ( b[p] shl (8-bitsleft) );
  224.             if currentcode <= 16 then
  225.             begin
  226.                 bitsleft := currentcode - 8;
  227.                 b[p] := b[p] shr bitsleft;
  228.             end else
  229.             begin
  230.                 inc(p);
  231.                 if p>=q then
  232.                 begin
  233.                     blocksize := 0;
  234.                     blockread( F, blocksize, 1);
  235.                     if blocksize>0 then
  236.                     begin
  237.                         p:=0;
  238.                         blockread( F, b, blocksize, q );
  239.                         if q<>blocksize then
  240.                         begin
  241.                             freemem( firstcodestack, 4096 );
  242.                             freemem( lastcodestack, 4096 );
  243.                             freemem( codestack, 8192 );
  244.                             freemem( linebuffer, fi.width );
  245.                             UnpackImage := UnexpectedEOF;
  246.                             exit;
  247.                         end;
  248.                     end else
  249.                     begin
  250.                         freemem( firstcodestack, 4096 );
  251.                         freemem( lastcodestack, 4096 );
  252.                         freemem( codestack, 8192 );
  253.                         freemem( linebuffer, fi.width );
  254.                         UnpackImage := UnexpectedEOF;
  255.                         exit;
  256.                     end;
  257.                 end;
  258.                 thiscode := thiscode or ( b[p] shl (16-bitsleft) );
  259.                 bitsleft := currentcode - 16;
  260.                 b[p] := b[p] shr bitsleft;
  261.             end;
  262.         end;
  263.         thiscode := thiscode and wordmasktable[codesize];
  264.         currentcode := thiscode;
  265.         if thiscode = bits2+1 then break;
  266.         if thiscode > nextcode then
  267.         begin
  268.             freemem( firstcodestack, 4096 );
  269.             freemem( lastcodestack, 4096 );
  270.             freemem( codestack, 8192 );
  271.             freemem( linebuffer, fi.width );
  272.             UnpackImage := BadCode;
  273.             exit;
  274.         end;
  275.         if thiscode = bits2 then
  276.         begin
  277.             nextcode := bits2+2;
  278.             codesize := bits + 1;
  279.             codesize2 := 1 shl codesize;
  280.             oldtoken := NoCode;
  281.             OldCode := NoCode;
  282.             continue;
  283.         end;
  284.         u := 0;
  285.         if thiscode = nextcode then
  286.         begin
  287.             if oldcode = NoCode then
  288.             begin
  289.                 freemem( firstcodestack, 4096 );
  290.                 freemem( lastcodestack, 4096 );
  291.                 freemem( codestack, 8192 );
  292.                 freemem( linebuffer, fi.width );
  293.                 UnpackImage := BadFirstCode;
  294.                 exit;
  295.             end;
  296.             firstcodestack^[u] := oldtoken;
  297.             inc( u );
  298.             thiscode := oldcode;
  299.         end;
  300.         while thiscode >= bits2 do
  301.         begin
  302.             firstcodestack^[u] := lastcodestack^[thiscode];
  303.             inc( u );
  304.             thiscode := codestack^[thiscode];
  305.         end;
  306.         oldtoken := thiscode;
  307.         while true do
  308.         begin
  309.             linebuffer^[byt] := thiscode;
  310.             inc( byt );
  311.             if byt >= fi.width then
  312.             begin
  313.                 GifOutLineProc( linebuffer^, line, fi.width );
  314.                 byt := 0;
  315.                 if fi.flags and $40 = $40 then
  316.                 begin
  317.                     line := line + inctable[pass];
  318.                     if line >= fi.depth then
  319.                     begin
  320.                         inc(pass);
  321.                         line := starttable[pass];
  322.                     end;
  323.                 end else inc(line);
  324.             end;
  325.             if u <= 0 then break;
  326.             dec( u );
  327.             thiscode := firstcodestack^[u];
  328.         end;
  329.         if (nextcode < 4096) and (oldcode <> NoCode) then
  330.         begin
  331.             codestack^[nextcode] := oldcode;
  332.             lastcodestack^[nextcode] := oldtoken;
  333.             in